Back to Main Menu

TRIM Integration (Assetic Python SDK)

Introduction

This article specifies the integration between Assetic and TRIM content management using the Assetic Python SDK and custom scripts to tailor the integration to site specific requirements.

NOTE   this integration supports HP Records Manager 8 (RM8) and HP Content Manager.  TRIM version 7 is not supported.  TRIM is used as the reference name in this article due to long history of the product under the name 'TRIM' 

 

The purpose of the integration is:

  1. Ensure that documents are managed within an organisation approved document management environment (TRIM)
  2. Minimise duplication of documents within Assetic and TRIM
  3. Provide ease of access to content for end users

 

Key Concepts

The integration assumes the following:

  1. Documents relevant to assets in Assetic will be managed in a TRIM folder (container) specific to each individual asset.
  2. Custom 'Additional Fields' in TRIM can be populated.  As an example, the asset 'Functional Location' may be recorded in an Additional Field to assist with searching for records in TRIM.
  3. Where Assetic Mobility generates new documents against an asset that content can be copied to TRIM.
    • Assetic work orders, work requests, and assessments are all associated with a single asset, hence documents that support these activities can be copied to the related asset folder in TRIM
  4. Contextual launch of a TRIM folder relevant to the current asset record in Assetic is achieved by recording the TRIM URI in Assetic.

Use Cases

The following use cases have been identified.

Use Case 1: Launch TRIM from Assetic

Since documents are maintained in TRIM and not Assetic, there is a requirement to contextually launch TRIM from Assetic to locate documents relevant to the current asset record in Assetic. 

 

This can be achieved using Web Drawer or Kapich EasyTRIM link

Integration Overview

Primary Direction of Data

No data flow.

Trigger

User via Assetic UI

Primary Results

TRIM is contextually launched to folder relevant to current Assetic record

Secondary Direction of Data

No data flow

Frequency/Scheduling

As initiated by user

Integration Type

Configuration of Assetic System Connector.

URL based launch of TRIM to relevant TRIM folder.

Integration Detail

Assetic has an inbuilt capability to contextually assemble a URL via the Assetic System Connector.  The System Connector may be configured within the Assetic UI, and is documented in the article Configuration of System Connector.

 

The System Connector is configured per asset category.  When assembling the URL the System Connector is able to utilise the data in the core fields of the current record, which differs for each Assetic module (asset register, or work order, or work request).  The Assetic Asset Id field is common to all of these modules.

Use Case 2: Create folder in TRIM corresponding with an Assetic asset

There may be a requirement to automate the creation of a folder (TRIM container) within TRIM that corresponds with an Assetic asset record.

 

When a new asset is created in Assetic a corresponding folder can be created in TRIM

Integration Overview

Primary Direction of Data

Assetic to TRIM.

Trigger

Upon creation of a new asset in Assetic

Primary Results

A TRIM container is created in TRIM

Secondary Direction of Data

A TRIM container identifier is returned to Assetic and the Assetic record updated to hold this identifier.

Frequency/Scheduling

A scheduled process to check for and process new Assetic records.  Frequency to be determined.

Integration Type

Assetic REST API’s

TRIM web service API’s

Scheduler such as Windows Scheduler

Integration Detail

The following integration work flow is used to ensure TRIM folders are created for Assetic asset records:

  1. The Assetic REST APIs are used to get a list of assets that do not have a TRIM folder ID in the Assetic asset field used to record external identifiers.
  2. The TRIM web service APIs are used to create a folder in TRIM. A check is first made to ensure the folder does not already exist.
  3. An TRIM folder identifier field is returned from TRIM upon folder creation and recorded against the asset in the Assetic asset field “External Other System 1 ID” (Appendix 1: Asset External Other System 1). Recording the TRIM folder ID acts as a flag to indicate that the asset has a corresponding folder in TRIM, and may also be utilised for verifying/auditing links.

Risks:

  1. TRIM is inaccessible or rejects folder creation. The integration design is such that the integration will attempt to create the folder the next time the integration is executed.
  2. Assetic is inaccessible. The integration design is such that the integration will attempt to create the folder the next time the integration is executed.
  3. The folder is updated in TRIM but the folder id is unable to be updated in Assetic. The integration design is such that the integration will manage folder creation to handle cases where the folder already exists, and will update Assetic with the folder ID.
  4. Folder already exists in TRIM. The folder may have been manually created in TRIM prior to the integration running. The integration design is such that the integration will manage folder creation to handle cases where the folder already exists, and will update Assetic with the folder ID.

The initial creation of folders in TRIM and updating of folder ID back to Assetic is a data migration activity outside of this Use Case. A one-off bulk process is more appropriate given the large number records involved.  The Assetic data exchange tool may be used to bulk update the field “External Other System 1 ID” with the TRIM folder ID.

Use Case 3: Copy Assetic generated content to TRIM

There may be a requirement to copy to TRIM document content generated from within Assetic.

Assetic Document Generation Background

Key points to assist with understanding document content generation in Assetic:

  1. The Assetic Mobility app is the only Assetic tool that uploads documents to the Assetic document repository. Currently the documents uploaded by this app are only ever photos, and there is no capacity to edit the document once it has been uploaded.
  2. The Assetic Mobility app requires documents to be held in the Assetic document repository so that documents can be accessed and uploaded in a consistent manner, and to avoid issues with access to documents held in repositories that are not external facing.
  3. The Assetic browser UI is unable to enforce the business rule that documents are only uploaded to TRIM. Users of the Assetic browser UI are currently able to upload documents to the Assetic document repository via the Assetic UI. There is currently no administrative function to disable this capability, hence this possibility needs to be factored into this integration.

 

Integration Overview

Primary Direction of Data

Assetic to TRIM.

Trigger

Upon upload of a new document to Assetic

Primary Results

A new document is copied from Assetic to TRIM

Secondary Direction of Data

TRIM Document ID returned and recorded against the Assetic document.

Frequency/Scheduling

A scheduled process to check for and process new Assetic documents.  Frequency to be determined.

Integration Type

Assetic REST API’s

TRIM web service API’s

Scheduler such as Windows Scheduler

Integration Detail

The following integration ensures documents uploaded to Assetic are moved/copied to TRIM:

  • The Assetic REST APIs get a list of documents in Assetic that do not have a reference to the TRIM document ID (implies they have not been copied to TRIM).
  • The Assetic REST API is used to get the document. The TRIM web service APIs are then used to upload the document to the TRIM folder associated with the asset.
    1. For documents that are still required in Assetic (active work order) the TRIM document ID for the newly created document is returned by TRIM. This TRIM ID is updated to the Assetic document ‘External ID’.  This acts as a flag to indicate the document has been copied to TRIM.
    2. For documents no longer required in Assetic the document is removed from Assetic via the Assetic REST API. 

Technical Detail

Integration Script Environment

Integration Script Overview

Development Language

Python 3 (or 2.7 if preferred)

Server Environment

A server provided by the site internal to site domain

Primary Results

A TRIM container is created in TRIM

Secondary Direction of Data

A TRIM container identifier is returned to Assetic and the Assetic record updated to hold this identifier.

Script Scheduling

Windows scheduler or other preferred scheduling tool

Logging

Script messages will be logged to a file.  Messages will be at various levels as per python log levels.

 

TRIM API

The TRIM web service API HPRMServiceAPI supports a POST operation to create and update documents and folders. 

 

TRIM generates a unique integer id (URI) for each record that is created. This URI is returned in the response body when a new folder or document is created.

 

In the case of ‘Folder’ creation, the URI of the folder will be recorded in Assetic against the asset. This URI used to specify the folder to place documents in when moving documents from Assetic to TRIM.

 

The TRIM API also supports a GET operation to get documents from TRIM using the TRIM record URI.

 

The TRIM API POST /HPRMServiceAPI /Record/ will be used for creating folders and document in Assetic

Files are uploaded as part of document creation as “Content Type”: “multipart/form-data”

 

Field Mappings

The following mappings represent the minimum requirements of the integration with respect to the TRIM API /HPRMServiceAPI /Record/

 

For TRIM Folder creation where the folder corresponds to an Assetic asset:

TRIM Label

TRIM API Field

Assetic Field

Comment

Unique Identifier

URI

External Other System 1 ID

When a folder is created in TRIM the returned TRIM URI will be recorded against the asset in Assetic.

Title

RecordTitle

Asset Name

This is the Asset Name in Assetic

External ID

RecordExternalReference

Asset ID

This is the user visible ID for the asset in Assetic

Container

RecordContainer

N/A

This is the TRIM parent folder URI to create the new folder in. Dependent on TRIM configuration.  Value configured in integration script.

Record Type

RecordRecordType

N/A

This is the TRIM record type name configured in TRIM for folders of this type. Value configured in integration script.

Classification

RecordClassification

N/A

Use a lookup file that maps Assetic Asset Category to TRIM Classification URI.

Author

RecordAuthor

N/A

Author URI. Value configured in integration script.

Record Number

RecordNumber

External Other System 2 ID

When a folder is created in TRIM the returned TRIM Record Number will be recorded against the asset in Assetic.

 

For TRIM Document creation/update where the document corresponds to a document generated within Assetic:

TRIM Label

TRIM API Field

Assetic Field

Comment

Unique Identifier

URI

External Reference ID

When a document is created in TRIM the returned TRIM URI will be recorded against the document in Assetic.

When a document in Assetic is updated, the URI is passed to TRIM to ensure the document is updated in TRIM

Title

RecordTitle

Asset ID

This is document label in Assetic.  If a Work Order document will be prefixed with work order ID.  If a Work Request document will be prefixed with Work Request number.

External ID

RecordExternalReference

Asset GUID

This is the internal unique GUID for the document in Assetic.

Container

RecordContainer

N/A

This is the TRIM folder URI to create the new document in.  The URI is based on the asset that the document belongs to.

Record Type

RecordRecordType

 

This is the TRIM record type name configured in TRIM for documents. Value configured in integration script.

Document

Files

Document

The Assetic document

Author

RecordAuthor

N/A

Author URI. Value configured in integration script.

 

To retrieve a document from TRIM the API GET /HPRMServiceAPI /Record/{0}/File/document is used where {0} is the TRIM URI of the document

TRIM API Field

Assetic Field

Comment

URI

External Reference ID

Use the URI recorded in Assetic to download the document

Deployment

The integration relies on system configurations in Assetic that will need to be applied per environment.

 

These include:

  • Search profile to get list of assets where “Ext. Other System 1 ID” is null/empty
  • System Connector configuration
  • Adding “HP_CM” to the “Ext. Other System 1 Name” picklist
  • Create integration login and generate token 

Use Case 1: Launch TRIM from Assetic

The format of the TRIM URL template using the Kapish EasyLink is as follows:

 

//trim/[record_number]/db=[]trimdb]&open where:

  • record_number is the TRIM record number. Held against the Asset in the field “External Other System 1 ID2”
  • trimdb is the TRIM database identifier, e.g. “TT” for the TRIM Test database.

 

These parameters are substituted in to the template at runtime.

 

The template is defined once, but referenced on a per category basis.  If there is a need to vary the URL on a per category basis this can be achieved using the one template additional parameters that can be varied per category.

 

A new browser tab is opened to launch this URL.

Use Case 2: Create folder in TRIM

Questions and Answers

The following FAQs have supported the technical design for this use case:

Question

Answer

What authentication method is required for TRIM web services?

NTLM

What metadata needs to accompany TRIM folder creation?

Title

External ID

Record Type

Author

Classification

If a folder of the same name already exists how will this be handled by the TRIM API?

Creates a second folder

How do I get a list of assets from Assetic that do not have a value in the asset attribute field “Ext. Other System 1 ID”

An Assetic asset search profile is configured via the Assetic UI with the search filter “Ext. Other System 1 ID is empty”.

Integration Flow

Technical Design

The following steps will be followed:

  1. The Assetic REST API endpoint GET /v2/search will be used to execute the precompiled search profile that returns assets that do not have a value in the asset attribute field “Ext. Other System 1 ID.
  2. The TRIM web service API will be used to create a folder in TRIM on a per category basis
  3. Use the Assetic Python SDK method “assetic.AssetTools.update_complete_asset” to update the asset attribute fields:
    1. “Ext. Other System 1 ID” – the TRIM folder URI
    2. “Ext. Other System 2 ID” – the TRIM record number
    3. “Ext. Other System 1 Name” – hardcode as “HP_CM”

Use Case 3: Copy Assetic generated content to TRIM

Questions and Answers

The following questions and answers have supported the technical design for this use case:

Question

Answer

What metadata needs to accompany TRIM document creation?

Title

External ID

Record Type

Author

Parent Container

If a document of the same name already exists how will this be handled by the TRIM API?

Creates a second document

Integration Flow

Technical Design

The following steps will are followed:

  1. The Assetic REST API endpoint GET /v2/search is used to execute the precompiled search profile that returns a list of all documents in Assetic.
  2. If the Assetic document field “External ID” is NULL then the document is uploaded to TRIM
    1. The Assetic REST API GET/v2/document/{id}/file is used to get the file. There is no need to save the file to disk prior to uploading to TRIM
    2. The document is uploaded to TRIM via the TRIM ‘record’ API
    3. The Assetic document “External ID” is updated with the TRIM document ID
  3. If the Assetic document “External ID” is NOT NULL and the document is not associated with an active work order, then the document is removed from Assetic.
    1. The Assetic REST API endpoint DELETE /v2/document/{id} is used to remove the file from Assetic. Note that the document metadata remains in Assetic, but the document has no associations and a delete status.

 

Test Cases

TRIM Folder Creation

The expected outcome is that there is a folder in TRIM corresponding to the asset in Assetic, and that each system holds the unique identifier of the other system.

Steps:

  1. Create a new asset in Assetic
  2. Verify new asset appears in the search list (refer Appendix 2)
  3. Run the integration script Assetic.SyncAssetFolders.py
  4. Verify the Folder is created in TRIM with the correct attributes. “External ID” is the Assetic asset ID
  5. Verify the Asset is updated (refer Appendix 1)
  6. Verify the Asset is no longer in the search list for Unsynced Asset Folders (refer Appendix 2)

 

Asset Documents – moved to TRIM

The expected outcome is that documents uploaded directly against an asset will be copied to TRIM into the corresponding TRIM folder and then deleted from Assetic

Steps:

  1. Upload one or more documents against an asset in Assetic which already has a corresponding TRIM folder
    1. A variation is to upload the document to an asset that does not have a TRIM folder. The integration should provide a warning and not process the document.  The document will remain in Assetic.
    2. A variation is to create a document link rather than upload a document. In this instance the search profile will not include the document link as a document to integrate, hence it will not be processed.
  2. Verify the document(s) appear in the search for unsynced asset documents search (refer Appendix 3)
  3. Run the integration script Assetic.SyncDocuments.py
  4. Check that the document(s) is uploaded to TRIM with the correct attributes. “External ID” is the Assetic document GUID.
  5. Verify the document has been removed from Assetic by opening the asset and going to the “Documents” tab.
  6. Verify the document is no longer in the search results list. **This test currently fails, the search results are not refreshing.  This is an issue in the Assetic platform that is awaiting resolution.  The integration script can be run again to verify that the integration detects that the file is flagged as deleted, and doesn’t create another document in TRIM.

 

Work Request/Work Order Documents

The expected outcome is that documents will be copied to TRIM, but will remain in Assetic until the Work Order/Work Request is closed or cancelled.

Notes:

  1. When a work order is created from a work request, any documents that were associated with the work request become associated with the work order. The document exists once, but is accessible via both work order and the work request.
  2. A work order is considered closed when the status is “Complete” or” Assessed”. It may also have a status of cancelled.
  3. A work request is considered closed when the status is “Resolved” or “Cancelled”

Steps – Work Order

  1. Create a work order
  2. Assign one or more documents to the work order
    1. A variation is to create a document link rather than upload a document. In this instance the search profile will not include the document link as a document to integrate, hence it will not be processed.
  3. Verify the document is in the search for work requests (refer Appendix 4)
  4. Run the integration script Assetic.SyncDocuments.py
  5. Check that the document(s) is uploaded to TRIM with the correct attributes. “External ID” is the Assetic document GUID.  Document title is prefixed with the Work Order Number
  6. Check that the document has been updated in Assetic with the TRIM URI in the external ID field
  7. Follow the steps to work order completion (status = “Complete” or “Assessed”)
    1. Alternative test is to change the status of the work order to ‘Cancelled’
  8. Verify the document is still in the search for work requests (refer Appendix 4)
  9. Run the integration script Assetic.SyncDocuments.py
  10. Check that the document(s) is remains unchanged in TRIM with the correct attributes. “External ID” is the Assetic document GUID.  Document title is prefixed with the Work Order Number
  11. Check that the document has been removed from the Assetic work order
  12. Verify the document is no longer in the search results list. **This test currently fails, the search results are not refreshing.  This is an issue in the Assetic platform that is awaiting resolution.  The integration script can be run again to verify that the integration detects that the file is flagged as deleted, and doesn’t create another document in TRIM.

Steps – Work Request initiated work order:

  1. Create a work request
  2. Assign one or more documents to the request
    1. A variation is to create a document link rather than upload a document. In this instance the search profile will not include the document link as a document to integrate, hence it will not be processed.
  3. Verify the document is in the search for work requests (refer Appendix 4)
    1. Alternate test is to run the integration prior to assigning an asset to the request. The document will not be uploaded to TRIM
  4. Run the integration script Assetic.SyncDocuments.py
  5. Check that the document(s) is uploaded to TRIM with the correct attributes. “External ID” is the Assetic document GUID.  Document title is prefixed with the Work Request Number
  6. Check that the document has been updated in Assetic with the TRIM URI in the external ID field
  7. Create a work order for the work request and follow the steps to work order completion. This will change the status of the work request to ‘Resolved’
    1. Alternative test is to change the status of the work request to ‘Cancelled’
  8. Verify the document is still in the search for work requests (refer Appendix 4)
  9. Run the integration script Assetic.SyncDocuments.py
  10. Check that the document(s) is remains unchanged in TRIM with the correct attributes. “External ID” is the Assetic document GUID.  Document title is prefixed with the Work Request Number
  11. Check that the document has been removed from the Assetic work request
  12. Verify the document is no longer in the search results list. **This test currently fails, the search results are not refreshing.  This is an issue in the Assetic platform that is awaiting resolution.  The integration script can be run again to verify that the integration detects that the file is flagged as deleted, and doesn’t create another document in TRIM.

 

Appendices

Appendix 1: Asset External Other System 1

Assetic provides a set of fields for recording external system identifier against an asset.

 

These fields can be navigated to via the Asset menu “Attributes”->” External Systems”.

 

Two fields will be populated in the “External Other System 1” section:

  • “Ext. Other System 1 ID” will be updated with the TRIM unique record identifier.
  • “Ext. Other System 1 Name” will be updated with the value “TRIM”
  • “Ext. Other System 2 ID” will be updated with the TRIM Record Number

Appendix 2: Search - TRIM unsynced folder (assets)

This search profile lists all assets that are not synced to TRIM, primarily based on the External ID being NULL.  Other filters may be included to refine the list.

 

The following fields are required:

  • Asset ID
  • Asset Name
  • Asset Category
  • External Other System 1 ID

Appendix 3: Search – TRIM Unsynced Asset Documents

This search profile lists all documents that are not synced to TRIM, primarily based on the External ID being NULL.  Other filters may be included to refine the list.  This search targets documents associated with assets.  A separate search filter is used for documents not directly associated with assets such as Work Requests and Work Orders.

 

The following fields are required:

  • ID
  • Asset ID
  • Status
  • External ID
  • Document Group
  • Document Subcategory
  • Document Link 

Appendix 4: TRIM Work Documents

This search returns all ‘Active’ documents associated with a work request and work order. 

 

The following fields are required:

  • ID
  • Asset ID
  • Status
  • External ID
  • Document Group
  • Document Subcategory
  • Document Link
  • Work Request Description
  • Work Order Friendly ID

Sync Asset Folders Sample Script 

The following sample creates a new folder in TRIM corresponding to an asset in Assetic.

 

It uses an Advanced Search Profile to search for assets that do not already have a TRIM folder reference in the Assetic field "External Other System 1 ID".

import assetic import csv #############Settings - make changes here############################### searchprofileid = "b8b6594a-7a55-e711-8187-025500ccdddb" const_classmappingfile = "Initial Asset Category mapping to TRIM Classifications for AMS.csv" #Ledger mapping file inifile = "c:/users/myself/assetic.ini"   #Has your login details loglevel = "Info"   #can also set as "Debug" for tracing errors logfile = None  #Log file #############End of Settings################################   asseticsdk = assetic.AsseticSDK(inifile,logfile,loglevel) doc = assetic.DocumentTools("HP_CM",asseticsdk.client) ##create an instance of the search api sapi = assetic.SearchApi()  def main(profile,searchfilter = None):     """     The given search profile and optional filter provides a list of     assets to create folders for     """     ##get list of assets     page = 1     pagesize = 2     sort = None      classificationdict = get_classification_mapping(const_classmappingfile)     if len(classificationdict) == 0:         return          while page < 2:         data = getassetsbysearch(profile,searchfilter,page,pagesize,sort)          for row in data:             assetid = row["Asset Id"]             assetcategory = row["Asset Category"]             assetname = row["Asset Name"]             try:                 classificationuri = classificationdict[assetcategory]             except:                 asseticsdk.logger.error(                     "Classification URI for category [{0}] "\                     "not defined.".format(assetcategory))             else:                 chk = create_folder_for_asset(assetid,assetname,classificationuri)                 print(chk)                 if chk == 1:                     ##error                     return         page = page + 1          def create_folder_for_asset(assetid,assetname,classificationuri):     """     Create a folder in HP CM for the given asset and classification     """          folder_rep = assetic.ECMSFolderRepresentation()      ##get settings     ecmsparent = None     ecmsfoldertype = "Parent Folder"     ecmsclassification = classificationuri      #set folder values     folder_rep.title = "{0} -{1}".format(assetid,assetname)     folder_rep.asseticid = assetid     folder_rep.ecmsfoldertype = ecmsfoldertype     folder_rep.ecmsclassification = classificationuri     return doc.new_folder_for_asset(assetid,folder_rep)       def getassetsbysearch(searchprofile,searchfilter,page,pagesize,sort):     """     Use advanced search profile to get a list of assets     """     kw = {"request_params_id": searchprofile,         "request_params_page":page,         "request_params_page_size":pagesize,         "request_params_sorts":sort,         "request_params_filters":searchfilter}     try:         sg = sapi.search_get(**kw)     except assetic.rest.ApiException as e:         asseticsdk.logger.error("Status {0}, Reason: {1} {2}".format(             e.status,e.reason,e.body))         return []      if page == 1:         totalresults = sg.get("TotalResults")         totalpages = sg.get("TotalPages")         asseticsdk.logger.info("Found {0} assets over {1} page(s)".format(             totalresults,totalpages))     else:         asseticsdk.logger.info("Processing page {0} of results".format(page))     resourcelist = sg.get("ResourceList")     resource = resourcelist[0]     data = resource.get("Data")     return data          def get_classification_mapping(classificationmappingfile):     """     Use a mapping file to get the TRIM URI for a classification based on     the Asset Category     """     category_classification = {}     category_classification["Buildings"]="3"     return category_classification     try:         with open(classificationmappingfile, newline = '') as csvfile:             reader = csv.reader(csvfile,delimiter=',')             for row in reader:                 category_classification[row[0]] = row[1]     except Exception as e:         asseticsdk.logger.error(             "Unable to get list of aset category to TRIM classifcations:"\             "\r\n\{0}".format(str(e)))     return category_classification  if __name__ == "__main__":     main(searchprofileid,None) 

Sync Documents Sample Script

The following sample uses an Advanced Search Profile to get a list of documents in Assetic.

 

It also uses an advanced search profile to get work order/work request documents where the work order/work request status is now 'closed' indicating the document may be removed from Assetic.

import assetic #############Settings - make changes here############################### #docsearchfilter = "ExternalId=''" search_profile = "cf80bd24-b057-e711-8187-064eec55e94f"  wkocloseprofile = "7c835ed1-b157-e711-8187-064eec55e94f" inifile = "c:/users/myself/assetic.ini"   #Has your login details loglevel = "Info"   #can also set as "Debug" for tracing errors logfile = None  #Log file #############End of Settings################################  asseticsdk = assetic.AsseticSDK(inifile,logfile,loglevel) docapi = assetic.DocumentApi(asseticsdk.client_for_docs) doctools = assetic.DocumentTools("HP_CM",asseticsdk.client_for_docs) ##create an instance of the search api sapi = assetic.SearchApi()  def main(searchprofile):     """     The given search filter provides a list of     documents to move to Trim     """     ##get list of assets     page = 1     pagesize = 7     sort = None      cnt_ok = 0     cnt_warn = 0     while page < 4:         data = getunsyncedbysearch(searchprofile,page,pagesize)          for row in data:             ecms_doc_rep = assetic.ECMSDocumentRepresentation()             ecms_doc_rep.ecmsdoctype = "Document"             ecms_doc_rep.ecmslevel = "5"             ecms_doc_rep.ecmsauthor = "103367"             ecms_doc_rep.ecmsclassification = "2"             doc_rep = assetic.Assetic3IntegrationRepresentationsDocumentRepresentation()             doc_rep.id = row["Id"]              ecms_doc_rep.assetic_doc_representation = doc_rep             asseticsdk.logger.info("Processing = {0}".format(doc_rep.id))              chk = doctools.move_document_to_ecms(ecms_doc_rep)             if chk == 1:                 ##error                 return             elif chk == -1:                 cnt_warn = cnt_warn + 1             else:                 asseticsdk.logger.info("Processed document {0}".format(                     doc_rep.id))                 cnt_ok = cnt_ok + 1         page = page + 1     asseticsdk.logger.info("Total successfully processed = {0}".format(cnt_ok))     asseticsdk.logger.info("Total skipped = {0}".format(cnt_warn))          def getunsyncedbysearch(searchprofile,page,pagesize):     """     Use advanced search profile to get a list of documents     Return:List of results or empty list of error     """     kw = {"request_params_id": searchprofile,         "request_params_page":page,         "request_params_page_size":pagesize}     try:         sg = sapi.search_get(**kw)     except assetic.rest.ApiException as e:         asseticsdk.logger.error("Status {0}, Reason: {1} {2}".format(             e.status,e.reason,e.body))         return []      if page == 1:         totalresults = sg.get("TotalResults")         totalpages = sg.get("TotalPages")         asseticsdk.logger.info("Found {0} documents over {1} page(s)".format(             totalresults,totalpages))     else:         asseticsdk.logger.info("Processing page {0} of results".format(page))     resourcelist = sg.get("ResourceList")     resource = resourcelist[0]     data = resource.get("Data")     return data         def delwkodocs(searchprofile):     """     The given search filter provides a list of     documents to move to Trim     """     ##get list of assets     page = 1     pagesize = 500     sort = None      cnt_ok = 0     cnt_warn = 0     while page:         data = getwkodocuments(searchprofile,page,pagesize)          for row in data:             docid = row["Id"]             asseticsdk.logger.info("Processing = {0}".format(docid))              chk = doctools.delete_doc(docid)             if chk > 0:                 ##error                 asseticsdk.logger.error("Process aborted due to error")                 return             else:                 asseticsdk.logger.info("Processed document {0}".format(                     doc_rep.id))                 cnt_ok = cnt_ok + 1         page = page + 1     asseticsdk.logger.info("Total successfully processed = {0}".format(cnt_ok))  def getwkodocuments(searchfilter,page,pagesize,sort):     """     Use document API search to get list of documents     Return:List of results or empty list of error     """     kwargs = {"request_params_page":page,               "request_params_page_size":pagesize,               "request_params_filters":searchfilter}     try:         doc = docapi.document_get(**kwargs)     except assetic.rest.ApiException as e:         asseticsdk.logger.error('Status {0}, Reason: {1} {2}'.format(             e.status,e.reason,e.body))         return []      if len(doc) == 0:         return []     if page == 1:         totalresults = doc[0].get("TotalResults")         totalpages = doc[0].get("TotalPages")         asseticsdk.logger.info("Found {0} documents over {1} page(s)".format(             totalresults,totalpages))     else:         asseticsdk.logger.info("Processing page {0} of results".format(page))     resourcelist = doc[0].get("ResourceList")      return resourcelist           if __name__ == "__main__":     main(search_profile)     delwkodocs(wkocloseprofile)